C 語言練習程式(6) -- 指標相關程式集錦(5)


Posted by nathan2009729 on 2022-07-30

此篇為Pointers in C Programming A Modern Approach to Memory Management, Recursive Data Structures, Strings, and Arrays這本書第五章筆記。
程式1:function-calls-multi.c

#include <assert.h>

void array_full_size(int A[10][10])
{
  // A becomes a pointer to length 10 arrays
  assert(sizeof A == sizeof(int (*)[10]));
  assert(sizeof *A == 10 * sizeof(int));
}

void array_incomplete_size(int A[][10])
{
  // A becomes a pointer to length 10 arrays
  assert(sizeof A == sizeof(int (*)[10]));
  assert(sizeof *A == 10 * sizeof(int));
}

void pointer(int (*A)[10])
{
  // A is explicitly a pointer to length 10 arrays
  assert(sizeof A == sizeof(int (*)[10]));
  assert(sizeof *A == 10 * sizeof(int));
}

int main(void)
{
  int A[10][10];
  assert(sizeof A == 10 * 10 * sizeof(int));
  array_full_size(A);
  array_incomplete_size(A);
  pointer(A);

  int B[5][10];
  assert(sizeof B == 5 * 10 * sizeof(int));
  // B's first dimension is wrong, but no warnings
  array_full_size(B);
  array_incomplete_size(B);
  pointer(B);

  int C[10][5];
  assert(sizeof C == 10 * 5 * sizeof(int));
  // You get warnings here, because the
  // second dimension doesn't match
  array_full_size(C);
  array_incomplete_size(C);
  pointer(C);

  return 0;
}

輸出:

程式2:function-calls.c

#include <stdio.h>

void pointer(int *a)
{
  printf("pointer: %zu %zu\n", sizeof a, sizeof *a);
}

void array(int a[])
{
  printf("array: %zu %zu\n", sizeof a, sizeof *a);
}

void array_with_size(int a[50])
{
  printf("array[50]: %zu %zu\n", sizeof a, sizeof *a);
}

void array_with_parameter_size(int n, int a[n])
{
  printf("array[n]: %zu %zu\n", sizeof a, sizeof *a);
}

void size_constrained(int a[static 4])
{
  printf("size constrained a[0] == %d\n", a[0]);
}

void indirect_size_constrained(int a[static 2])
{
  size_constrained(a); // No warning, though 2 < 4
}

void pointer_to_array(int (*a)[3])
{
  printf("*a: %zu = %zu x %zu\n",
         sizeof *a, sizeof *a / sizeof **a, sizeof **a);
}

void pointer_to_array_n(int n, int (*a)[n])
{
  printf("*a with n = %d: %zu = %zu x %zu\n",
         n, sizeof *a,
         sizeof *a / sizeof **a, sizeof **a);
}

void indirect_pointer_to_array(int n, int (*array)[1])
{
  pointer_to_array(array); // Warning, ok bcause 1 < 3
}

int main(void)
{
  int n = 100;
  int a[n]; a[0] = 42;
  int b[2]; b[0] = 13;
  int *p = b;

  printf("declared: %zu %zu\n", sizeof a, sizeof *a);
  pointer(a);
  array(a);
  array_with_size(a); // Ok, 100 > 5
  array_with_size(b); // No warning although 2 < 50
  array_with_parameter_size(n, a); // Ok, a has size n
  array_with_parameter_size(n, b); // No warning but 2 < 100

  size_constrained(b); // Warning (correct, 2 < 4)
  size_constrained(p); // No warning, even though p == b

  indirect_size_constrained(b); // No warning...

  pointer_to_array(&a); // Ok, 100 > 3
  pointer_to_array(&b); // Warning (correct 2 < 3)
  pointer_to_array_n(10, &a); // Ok since 100 > 10
  pointer_to_array_n(50, &b); // No warning, although 2 < 50

  pointer_to_array(p); // Warning, ok since p does not point to array
  pointer_to_array_n(10, p); // Warning, ditto

  indirect_pointer_to_array(2, b);


  return 0;
}

輸出:

declared: 400 4
pointer: 8 4
array: 8 4
array[50]: 8 4
array[50]: 8 4
array[n]: 8 4
array[n]: 8 4
size constrained a[0] == 13
size constrained a[0] == 13
size constrained a[0] == 13
*a: 12 = 3 x 4
*a: 12 = 3 x 4
*a with n = 10: 40 = 10 x 4
*a with n = 50: 200 = 50 x 4
*a: 12 = 3 x 4
*a with n = 10: 40 = 10 x 4
*a: 12 = 3 x 4

程式3:function-calls.c

#include <stdio.h>
#include <assert.h>

int main(void)
{
  int array[] = { 0, 1, 2, 3, 4 };
  int n = sizeof array / sizeof *array;
  int *jp = array;

  for (int i = 0; i < 5; i++) {
    assert(array + i == jp + i);
    assert(array[i] == jp[i]);
    assert(array[i] == *(array + i));
    assert(jp[i] == *(jp + i));

    assert(i[array] == i[jp]);
  }

  int *ip = array;
  char *p = (char *)array;
  for (int i = 0; i < n; i++) {
    printf("%p %p %p\n",
           // int array has the right offset
           (void *)(array + i),
           // int * has the right offset
           (void *)(ip + i),
           // void * jumps in bytes...
           (void *)(p + i * sizeof(int)));
  }

  char *end = (char *)array + sizeof array;
  for (ip = array, p = (char *)array;
       p != end;
       ip++, p += sizeof *ip) {
    printf("%p %p\n", (void *)ip, (void *)p);
  }

  return 0;
}

輸出:

0x7fff00748fa0 0x7fff00748fa0 0x7fff00748fa0
0x7fff00748fa4 0x7fff00748fa4 0x7fff00748fa4
0x7fff00748fa8 0x7fff00748fa8 0x7fff00748fa8
0x7fff00748fac 0x7fff00748fac 0x7fff00748fac
0x7fff00748fb0 0x7fff00748fb0 0x7fff00748fb0
0x7fff00748fa0 0x7fff00748fa0
0x7fff00748fa4 0x7fff00748fa4
0x7fff00748fa8 0x7fff00748fa8
0x7fff00748fac 0x7fff00748fac
0x7fff00748fb0 0x7fff00748fb0

程式4:jagged.c

#include <stdio.h>
#include <assert.h>

int main(void)
{
  double *A[] = {
    (double[]){1},
    (double[]){2, 3},
    (double[]){4, 5, 6}
  };

  int n = sizeof A / sizeof *A;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j <= i; j++) {
      printf("%2.2f ", A[i][j]);
    }
    printf("\n");
  }

  // not true: assert(sizeof A == 6 * sizeof(double));
  assert(sizeof A == 3 * sizeof(double *));
  assert(sizeof A[0] == sizeof(double *));
  assert(sizeof A[1] == sizeof(double *));
  assert(sizeof A[2] == sizeof(double *));

  double row0[] = {1};
  double row1[] = {2, 3};
  double row2[] = {4, 5, 6};
  double *B[] = { row0, row1, row2 };

  assert(sizeof B == sizeof A);
  assert(sizeof B[0] == sizeof A[0]);

  double **p_A = A;
  assert(p_A[0] == A[0]);
  assert(p_A[1] == A[1]);
  assert(p_A[0][0] == A[0][0]);

  double *p_A1 = A[1];
  assert(p_A1[0] == A[1][0]);
  assert(p_A1[1] == A[1][1]);

  return 0;
}

輸出:

1.00 
2.00 3.00 
4.00 5.00 6.00


注意以下這些宣告方式

double *A[] = {
    (double[]){1},
    (double[]){2, 3},
    (double[]){4, 5, 6}
  };
double row0[] = {1};
double row1[] = {2, 3};
double row2[] = {4, 5, 6};
double *B[] = { row0, row1, row2 };

程式5:matrix.c(2*2矩陣相乘)

#include <stdio.h>

void mult(int n, int m, int l,
          double C[n][m],
          double const A[n][l],
          double const B[l][m])
{
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      double x = 0.0;
      for (int k = 0; k < l; k++) {
        x += A[i][k] * B[k][j];
      }
      C[i][j] = x;
    }
  }
}

void print_matrix(int n, int m, double const A[n][m])
{
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      printf("%2.2f ", A[i][j]);
    }
    printf("\n");
  }
}

int main(void)
{
  double A[2][3] = {
    { 1, 2, 3 },
    { 4, 5, 6 }
  };
  double B[3][2] = {
    { 1, 2 },
    { 3, 4 },
    { 5, 6 }
  };
  double C[2][2];
  mult(2, 2, 3, C, A, B);

  print_matrix(2, 2, C);

  return 0;
}

輸出:

22.00 28.00 
49.00 64.00

程式6:multi-dim-repr-2.c

#include <stdio.h>

int main(void)
{
  int C[2][2][3] = {
    { { 1, 2, 3 }, {  4,  5,  6 } },
    { { 7, 8, 9 }, { 10, 11, 12 } }
  };

  int dim1 = sizeof C / sizeof C[0];
  int dim2 = sizeof C[0] / sizeof C[0][0];
  int dim3 = sizeof C[0][0] / sizeof C[0][0][0];

  printf("C dimensions %d x %d x %d\n", dim1, dim2, dim3);

  printf("First element in each row: ");
  int (*first_dim_p)[2][3] = C;
  int (*first_end)[2][3] = C + dim1;
  for ( ; first_dim_p < first_end; first_dim_p++) {
    printf("%d ", *(int*)first_dim_p);
  }
  printf("\n");

  printf("First element in each column: ");
  int (*second_dim_p)[3] = (int (*)[3])C;
  int (*second_end)[3] = (int (*)[3])C + dim1 * dim2;
  for ( ; second_dim_p < second_end; second_dim_p++) {
    printf("%d ", *(int*)second_dim_p);
  }
  printf("\n");

  return 0;
}

輸出:

C dimensions 2 x 2 x 3
First element in each row: 1 7 
First element in each column: 1 4 7 10

程式7:multi-dim-repr.c

#include <assert.h>

int main(void)
{
  int A[2][3] = {
    { 1, 2, 3 },
    { 4, 5, 6 }
  };

  assert(sizeof A == 2 * 3 * sizeof(int));
  assert(sizeof *A == 3 * sizeof(int));
  assert(sizeof A[0] == 3 * sizeof(int));
  assert(sizeof A[0][0] == sizeof(int));

  int *p = (int *)A;
  for (int i = 0; i < 2; i++) {
    // p now points to the first element in row i
    assert(p == A[i]);
    for (int j = 0; j < 3; j++) {
      // p points to column j in row i
      assert(A[i] + j == p);
      assert(&A[i][j] == p);
      assert(A[i][j] == *p);
      p++;
    }
  }

  int B[2][2][3] = {
    { { 1, 2, 3 }, {  4,  5,  6 } },
    { { 7, 8, 9 }, { 10, 11, 12 } }
  };

  assert(sizeof B == 2 * 2 * 3 * sizeof(int));
  assert(sizeof B[0] == 2 * 3 * sizeof(int));
  assert(sizeof B[0][0] == 3 * sizeof(int));
  assert(sizeof B[0][0][0] == sizeof(int));

  p = (int *)B;
  for (int i = 0; i < 2; i++) {
    // p now points to row i
    assert(p == (int *)B[i]);
    for (int j = 0; j < 2; j++) {
      // p now points to column j in row i
      assert(p == (int *)(B[i] + j));
      for (int k = 0; k < 3; k++) {
        // p now points to the k'th element in B[i][j]
        assert(B[i][j] + k == p);
        assert(&B[i][j][k] == p);
        assert(B[i][j][k] == *p);
        p++;
      }
    }
  }

  return 0;
}

輸出:

程式8:pointers-arrays.c

#include <stdio.h>
#include <assert.h>

void not_what_you_want(int array[])
{
  // sizeof(array) is sizeof(int *) here!
  printf("%zu\n", sizeof array);
  // Here, the array and the address of the array
  // are different. array is a local variable
  // that holds a pointer to the array!
  printf("%p %p\n", (void *)array, (void *)&array);
}

int main(void)
{
  int array[] = { 1, 2, 3, 4, 5 };
  int *ap = array;
  int (*ap2)[] = &array;

  printf("sizeof array == %zu, sizeof ap == %zu, sizeof ap2 == %zu, sizeof *ap2\n",
         sizeof array, sizeof ap, sizeof ap2);
  printf("%p %p %p %p %p %p\n", (void *)array, (void *)&array,
         (void *)ap, (void *)&ap, (void *)ap2, (void *)&ap2);

  int n = sizeof array / sizeof *array;
  for (int i = 0; i < n; i++) {
    assert(array[i] == ap[i]);
    assert(array + i == ap + i);
    assert(*(array + i) == *(ap + i));
  }

  return 0;
}

輸出:

sizeof array == 20, sizeof ap == 8, sizeof ap2 == 8, sizeof *ap2
0x7fff3ecc55e0 0x7fff3ecc55e0 0x7fff3ecc55e0 0x7fff3ecc55d0 0x7fff3ecc55e0 0x7fff3ecc55d8

程式9:pointers-to-arrays.c

#include <stdio.h>

int main(void)
{
  int array[10];
  int (*ap1)[] = &array;
  int (*ap2)[10] = &array;
  int (*ap3)[5] = &array; // Warning
  int (*ap4)[20] = &array; // Warning
  int *ip = array;

  printf("%p, sizeof array == %zu\n", (void *)array, sizeof array);
  // We cannot get sizeof *ap1, it is an incomplete type.
  printf("%p\n", (void *)*ap1);
  printf("%p, sizeof *ap2 == %zu (%zu)\n",
         (void *)*ap2, sizeof *ap2, 10 * sizeof(int));
  printf("%p, sizeof *ap3 == %zu (%zu)\n",
         (void *)*ap3, sizeof *ap3, 5 * sizeof(int));
  printf("%p, sizeof *ap4 == %zu (%zu)\n",
         (void *)*ap4, sizeof *ap4, 20 * sizeof(int));
  printf("%p, sizeof *ip == %zu (%zu)\n",
         (void *)ip, sizeof ip, sizeof(int *));

  return 0;
}

輸出:

0x7ffe61ad0000, sizeof array == 40
0x7ffe61ad0000
0x7ffe61ad0000, sizeof *ap2 == 40 (40)
0x7ffe61ad0000, sizeof *ap3 == 20 (20)
0x7ffe61ad0000, sizeof *ap4 == 80 (80)
0x7ffe61ad0000, sizeof *ip == 8 (8)

程式10:simple.c

#include <stdio.h>

void add_array(int n, int array[n], int x)
{
  for (int i = 0; i < n; i++) {
    array[i] += x;
  }
}

void add_pointers(int *begin, int *end, int x)
{
  for ( ; begin < end; begin++) {
    *begin += x;
  }
}

int sum_array(int n, int array[n])
{
  int sum = 0;
  for (int i = 0; i < n; i++) {
    sum += array[i];
  }
  return sum;
}

int sum_pointers_(int *begin, int *end)
{
  int sum = 0;
  for ( ; begin < end; begin++) {
    sum += *begin;
  }
  return sum;
}

int sum_pointers(int *begin, int *end)
{
  int sum = 0;
  while (begin < end) {
    sum += *begin++;
  }
  return sum;
}

void swap_array(int array[], int i, int j)
{
  int tmp = array[j];
  array[j] = array[i];
  array[i] = tmp;
}

void reverse_array(int n, int array[n])
{
  for (int i = 0; i < n/2; i++) {
    swap_array(array, i, n - i - 1);
  }
}

void swap_pointers(int *i, int *j)
{
  int tmp = *i;
  *i = *j;
  *j = tmp;
}

void reverse_pointers(int *begin, int *end)
{
  if (end <= begin) return;
  end--; // point to last element
  while (begin < end) {
    swap_pointers(begin++, end--);
  }
}

void print_array(int n, int array[n])
{
  printf("[ ");
  for (int i = 0; i < n; i++)
    printf("%d ", array[i]);
  printf("]\n");
}

int main(void)
{
  int array[] = { 1, 2, 3, 4, 5 };
  int n = sizeof array / sizeof *array;
  add_array(n, array, 2);
  print_array(n, array);

  add_pointers(array, array + n, -2);
  print_array(n, array);

  printf("%d %d\n",
         sum_array(n, array),
         sum_pointers(array, array + n));

  reverse_array(n, array);
  print_array(n, array);

  reverse_pointers(array, array + n);
  print_array(n, array);

  return 0;
}

輸出:

[ 3 4 5 6 7 ]
[ 1 2 3 4 5 ]
15 15
[ 5 4 3 2 1 ]
[ 1 2 3 4 5 ]

程式11:void.c

#include <stdio.h>

int main(int argc, char **argv)
{
  void *vp = 0;
  char *cp = 0;
  int  *ip = 0;
  long *lp = 0;

  for (int i = 0; i < 5; i++) {
    char *p = vp; // so we can do arithmetic
    printf("char: %p %p ",  cp + i, p + i * sizeof(char));
    printf("int: %p %p ",   ip + i, p + i * sizeof(int));
    printf("long: %p %p\n", lp + i, p + i * sizeof(long));
  }

  return 0;
}

輸出:

char: (nil) (nil) int: (nil) (nil) long: (nil) (nil)
char: 0x1 0x1 int: 0x4 0x4 long: 0x8 0x8
char: 0x2 0x2 int: 0x8 0x8 long: 0x10 0x10
char: 0x3 0x3 int: 0xc 0xc long: 0x18 0x18
char: 0x4 0x4 int: 0x10 0x10 long: 0x20 0x20

#c pointer #c array #matrix







Related Posts

Typescript express 打造Twitter專案 Part1

Typescript express 打造Twitter專案 Part1

利用 Wit.ai 讓你的 Messenger Bot 更聰明!

利用 Wit.ai 讓你的 Messenger Bot 更聰明!

為什麼寫在 label 上的 click 事件會觸發兩次?

為什麼寫在 label 上的 click 事件會觸發兩次?


Comments